#include "fileTransfer.h"

/*
 * sockfd     通信套接字
 * file_path  上传文件本地路径
 */
int upload(int sockfd, const char *file_path)
{
    // 处理文件路径，截取文件名
    char filename[256];
    const char *last_slash = strrchr(file_path, '/');
    if (last_slash != NULL)
    {
        strcpy(filename, last_slash + 1);
    }
    else
    {
        strcpy(filename, file_path);
    }

    // 定义小火车
    train_t train;

    // 用小火车发送文件名
    train.length = strlen(filename);
    strncpy(train.data, filename, train.length);
    train.data[train.length] = '\0';
    send(sockfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

    // 打开本地需要上传的文件
    int fd = open(file_path, O_RDONLY);

    // 获取文件长度（实现进度条打印）
    struct stat statbuf;
    fstat(fd, &statbuf);

    off_t filesize = statbuf.st_size;
    printf("filesize = %ld\n", filesize);

    off_t cur_size = 0;             // 已经上传的文件数据量
    off_t last_size = 0;            // 上次打印的cur_size
    off_t slice = filesize / 10000; // 分片

    printf("upload begin\n");

    // 传输文件
    if (filesize > big_file_size) // 大文件：mmap 实现零拷贝
    {
        ftruncate(fd, filesize);

        // 建立映射区
        char *p = (char *)mmap(NULL, filesize,
                               PROT_READ, MAP_SHARED, fd, 0); // 权限和open一致：只读

        off_t offset = 0; // 偏移量
        while (1)
        {
            if (offset >= filesize) // 跳出循环条件
            {
                break;
            }
            if (filesize - offset > 1000) // 未传输数据量
            {
                train.length = 1000;
            }
            else // 最后一次传输
            {
                train.length = filesize - offset;
            }

            send(sockfd, &train.length, sizeof(train.length), MSG_NOSIGNAL);
            send(sockfd, p + offset, train.length, MSG_NOSIGNAL); // 从内核态到内核态
            offset += train.length;

            // 打印进度条
            cur_size += train.length;
            // 当前发送文件数据量 - 上次打印时发送文件数据量 > 分片，更新进度条
            if (cur_size - last_size > slice)
            {
                printf("send %.2lf%%\r", 100.0 * cur_size / filesize); // 打印已经完成发送的百分比
                fflush(stdout);                                        // 刷新缓冲区
                last_size = cur_size;                                  // 更新上一次
            }
        }

        train.length = 0;
        send(sockfd, &train.length, sizeof(train.length), MSG_NOSIGNAL); // 发一个空车厢

        // 释放映射区
        munmap(p, filesize);
    }
    else // 小文件
    {
        while (1)
        {
            bzero(train.data, sizeof(train.data));                       // 清空车厢
            ssize_t ret_read = read(fd, train.data, sizeof(train.data)); // 将文件内容读取到火车厢
            train.length = ret_read;                                     // 设置火车头
            send(sockfd, &train, sizeof(train.length) + train.length, MSG_NOSIGNAL);

            // 打印进度条
            cur_size += train.length;
            // 当前发送文件数据量 - 上次打印时发送文件数据量 > 分片，更新进度条
            if (cur_size - last_size > slice)
            {
                printf("send %.2lf%%\r", 100.0 * cur_size / filesize); // 打印已经完成发送的百分比
                fflush(stdout);                                        // 刷新缓冲区
                last_size = cur_size;                                  // 更新上一次
            }
            if (ret_read == 0) // 最后一次read已经没有数据了，ret=0，此时是一个空车厢
            {
                break;
            }
        }
    }
    printf("upload 100.00%%\n");

    close(fd);
    return 0;
}
